#include "tcp_receiver.hh"

// Dummy implementation of a TCP receiver

// For Lab 2, please replace with a real implementation that passes the
// automated checks run by `make check_lab2`.

template <typename... Targs>
void DUMMY_CODE(Targs &&.../* unused */) {}

using namespace std;

bool TCPReceiver::segment_received(const TCPSegment &seg) {
  auto &header = seg.header();
  auto length = seg.length_in_sequence_space();
  if (header.syn) {
    if (_syn) {
      return false;
    }
    _syn = true;
    _isn = header.seqno;
    length -= 1;
    if (length == 0) {
      return true;
    }
  } else if (!_syn) {
    return false;
  }

  if (header.fin) {
    if (_fin) {
      return false;
    }
    _fin = true;
    // 这里可以不减一，让FIN通过窗口范围检测
    // length -= 1;
  }
  auto checkpoint = _reassembler.get_next_index();
  // 这里的加1其实为了建立连接时SYN占用的seqno
  auto abs_seqno = unwrap(header.seqno, _isn, checkpoint);
  auto lower = get_window_left();
  // 发过来一个空包也不能忽略，虽然没携带实际信息，但可以能有结束标识符；
  // 这里代表让其通过窗口范围检测
  // length = length == 0 ? length + 1 : length;
  // 判断是否在窗口内
  if (abs_seqno >= lower + window_size() || (abs_seqno + length <= lower && !header.syn)) {
    return false;
  }
  auto stream_index = abs_seqno - 1 + (header.syn);
  _reassembler.push_substring(seg.payload().copy(), stream_index, header.fin);
  return true;
}

optional<WrappingInt32> TCPReceiver::ackno() const {
  if (!_syn) {
    return std::nullopt;
  }
  return wrap(get_window_left(), _isn);
}

size_t TCPReceiver::window_size() const { return _capacity - _reassembler.stream_out().buffer_size(); }
